﻿using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using ST.Buz.Base.Entity;
using ST.Buz.Base.ViewModel;
using ST.Buz.Service;
using ST.Common.Util;
using ST.Common.Util.Model;
using ST.Common.Util.Mvc;
using ST.Common.Util.Security;
using ST.Common.Util.Text;
using ST.WX.Common;
using ST.WX.MP;
using ST.WX.MP.Menu;
using ST.WX.MP.TplMsg;
using ST.WX.MP.TplMsg.Model;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;

namespace ST.Buz.Web.Controllers
{
	/// <summary>
	/// 微信公众号相关功能（此文件应仅在oauth项目中使用，用来保证同一个公众号的access_token有效）
	/// </summary>
	[Route("wx/mp")]
	public class WX_MPController : MyBaseController
	{
		private readonly WXMPBaseApi mpBaseApi;
		private readonly WXMenuApi menuApi;
		private readonly WXTplMsgApi tplMsgApi;
		//private readonly IUserService userServ;
		//private readonly ISessionService sessionServ;
		private readonly IServiceSysOAuth oauthServ;
		private readonly IServiceWXSession wxSessionServ;
		private readonly IServiceWXAppConfig wxAppConfigServ;

		public WX_MPController(ILogger<WX_MPController> _logger, WXMPBaseApi _mpBaseApi
			, WXMenuApi _menuApi
			, WXTplMsgApi _tplMsgApi
			//, IUserService _userServ, ISessionService _sessionServ, IOAuthService _oauthServ)
			, IServiceSysOAuth _oauthServ
			, IServiceWXSession _wxSessionServ
			, IServiceWXAppConfig _wxAppConfigServ)
			: base(_logger)
		{
			mpBaseApi = _mpBaseApi;
			menuApi = _menuApi;
			tplMsgApi = _tplMsgApi;

			//userServ = _userServ;
			//sessionServ = _sessionServ;
			oauthServ = _oauthServ;
			wxSessionServ = _wxSessionServ;
			wxAppConfigServ = _wxAppConfigServ;
		}

		[HttpGet("notify")]
		public IActionResult WXNotify(string appid, string signature, string timestamp, string nonce, string echostr)
		{
			try
			{
				if (logger.IsEnabled(LogLevel.Debug))
				{
					logger.LogDebug("微信推送参数->appid:{0},signature:{1},timestamp:{2},nonce:{3},echostr:{4}",
						appid, signature, timestamp, nonce, echostr);
				}
				WX_AppConfig wxConfig = wxAppConfigServ.LoadOrGet(appid);
				if (!mpBaseApi.BaseApi.CheckSignature(wxConfig.AppToken, signature, timestamp, nonce))
				{
					throw new Exception("微信签名校验失败");
				}

				return Content(echostr);
			}
			catch (Exception ex)
			{
				logger.LogError(ex, "处理微信推送消息出错");
				return Content(ex.Message);
			}
		}

		[HttpPost("notify")]
		public IActionResult WXHandler(string appid, string signature, string timestamp, string nonce, string echostr)
		{
			try
			{
				if (logger.IsEnabled(LogLevel.Debug))
				{
					logger.LogDebug("微信推送参数->appid:{0},signature:{1},timestamp:{2},nonce:{3},echostr:{4}",
						appid, signature, timestamp, nonce, echostr);
				}
				if (!mpBaseApi.BaseApi.CheckSignature(appid, signature, timestamp, nonce))
				{
					throw new Exception("校验微信签名失败");
				}

				#region 接收从微信后台POST过来的数据并解析
				string resultXml = string.Empty;
				StringBuilder buf = new StringBuilder();
				using (System.IO.Stream s = Request.Body)
				{
					int count = 0;
					byte[] buffer = new byte[1024];
					while ((count = s.Read(buffer, 0, buffer.Length)) > 0)
					{
						buf.Append(Encoding.UTF8.GetString(buffer, 0, count));
					}
				}
				resultXml = buf.ToString();
				if (logger.IsEnabled(LogLevel.Debug))
				{
					logger.LogDebug("微信推送内容->" + resultXml);
				}
				if (string.IsNullOrEmpty(resultXml))
				{
					throw new BuzException("微信推送内容为空");
				}
				Dictionary<string, string> dicContent = new Dictionary<string, string>();
				XmlDocument xmlDoc = new XmlDocument();
				xmlDoc.XmlResolver = null;//修复XML外部实体注入漏洞(XML External Entity Injection，简称 XXE)
				xmlDoc.LoadXml(resultXml);
				XmlNode nodeRoot = xmlDoc.DocumentElement;
				XmlNodeList nodes = nodeRoot.ChildNodes;
				foreach (XmlNode xn in nodes)
				{
					if (xn.NodeType == XmlNodeType.Element)
					{
						XmlElement xe = (XmlElement)xn;
						dicContent.Add(xe.Name, xe.InnerText);
					}
				}
				if (dicContent.ContainsKey("Event"))
				{
					switch (dicContent["Event"])
					{
						case "subscribe"://关注事件
							DoSubscribe(dicContent);
							break;
						case "SCAN":
							DoScan(dicContent);//已关注之后，EventKey直接为场景值
							break;
					}
				}
				#endregion
				return new EmptyResult();
			}
			catch (Exception ex)
			{
				logger.LogError(ex, "处理微信推送消息出错");
				return new EmptyResult();
			}
		}

		/// <summary>
		/// 初始化菜单
		/// </summary>
		/// <returns></returns>
		[HttpGet("initmenu")]
		public IActionResult InitMenu()
		{
			try
			{
				return new EmptyResult();
			}
			catch (Exception ex)
			{
				logger.LogError(ex, "初始化公众号菜单出错");
				return new EmptyResult();
			}
		}

		[HttpGet("info")]
		public IActionResult ShowInfo(string appid, string nonce)
		{
			try
			{
				if (string.Compare(EncryptHelper.SHA1Hash(appid + DateTime.Now.ToString("yyyyMMdd")), nonce) != 0)
				{
					throw new WXException("访问非法");
				}
				var appConfig = wxAppConfigServ.LoadOrGet(appid);
				string accessToken = mpBaseApi.BaseApi.GetAccessToken(appConfig.AppID, appConfig.AppSecret);
				return new JsonResultBase(accessToken);
			}
			catch (WXException ex)
			{
				logger.LogError(ex, "获取App信息出错");
				return new JsonResultBase(false, "获取App信息出错，" + ex.Message, (int)HttpStatusCode.InternalServerError);
			}
			catch (Exception ex)
			{
				logger.LogError(ex, "获取App信息出错");
				return new JsonResultBase(false, "获取App信息出错，" + ex.Message, (int)HttpStatusCode.InternalServerError);
			}
		}

		[HttpGet("jssdk")]
		[HttpPost("jssdk")]
		public IActionResult GenJSSDK(string appid, string url, string callback)
		{
			//Response.Headers.Add("Access-Control-Allow-Origin", "*");
			try
			{
				if (string.IsNullOrEmpty(appid))
				{

				}
				if (string.IsNullOrEmpty(url))
				{
					url = Request.Path;
					//url = Request.GetDisplayUrl();
				}
				var wxJSSDK = new WX_JSSDK();
				WX_AppConfig wxConfig = wxAppConfigServ.LoadOrGet(appid);
				string jsTicket = mpBaseApi.GetJSTicket(wxConfig);
#if DEBUG
				wxJSSDK.debug = true;
#else
				wxJSSDK.debug = false;
#endif
				wxJSSDK.appId = wxConfig.AppID;
				wxJSSDK.nonceStr = RandomGenerator.GetNonceStr();
				wxJSSDK.timestamp = RandomGenerator.GetTimeStamp();
				wxJSSDK.signature = mpBaseApi.Signature(wxJSSDK.nonceStr, jsTicket, wxJSSDK.timestamp.ToString(), url);
				if (string.IsNullOrEmpty(callback))
				{
					return new JsonResultBase(wxJSSDK);
				}
				else
				{
					var jsonStr = TextHelper.SerializeObject(new ResultData(wxJSSDK));
					return Content($"{callback}({jsonStr})");
				}
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				if (string.IsNullOrEmpty(callback))
				{
					return new JsonResultBase(false, "请求出错，" + ex.Message, (int)HttpStatusCode.InternalServerError);
				}
				else
				{
					var jsonStr = TextHelper.SerializeObject(new ResultData(false, "请求出错，" + ex.Message, (int)HttpStatusCode.InternalServerError));
					return Content($"{callback}({jsonStr})");
				}
			}
		}

		[HttpGet("oauth")]
		public IActionResult OAuth(string appid, string code, string state, string page)
		{
			//Response.Headers.Add("Access-Control-Allow-Origin", "*");
			try
			{
				if (string.IsNullOrEmpty(code))
				{
					var redirectUri = string.Concat(Request.Scheme,
							"://",
							Request.Host.ToUriComponent(),
							Request.PathBase.ToUriComponent(),
							Request.Path.ToUriComponent(),
							Request.QueryString.ToUriComponent());

					if (logger.IsEnabled(LogLevel.Debug))
					{
						logger.LogDebug("微信公众号登录重定向地址->{0}", appid, code, state, page);
					}

					//snsapi_base,snsapi_userinfo
					//若用户禁止授权，则重定向后不会带上code参数，仅会带上state参数
					return Redirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + HttpUtility.UrlEncode(redirectUri) + "&response_type=code&scope=snsapi_base&state=" + state + "#wechat_redirect");
				}
				else
				{
					if (logger.IsEnabled(LogLevel.Debug))
					{
						logger.LogDebug("微信公众号登录->appid：{0},code：{1},state：{2},page：{3}", appid, code, state, page);
					}
					WX_AppConfig wxConfig = wxAppConfigServ.LoadOrGet(appid);
					var oauthResult = mpBaseApi.GetOAuthAccessToken(wxConfig.AppID, wxConfig.AppSecret, code, null);
					if (oauthResult == null)
					{
						throw new BuzException("获取网页授权凭证ACCESS_TOKEN为空");
					}
					string accessToken = mpBaseApi.BaseApi.GetAccessToken(wxConfig.AppID, wxConfig.AppSecret);
					if (string.IsNullOrEmpty(accessToken))
					{
						throw new BuzException("获取普通授权ACCESS_TOKEN为空");
					}
					var userInfo = mpBaseApi.GetUserInfo(accessToken, oauthResult.openid);
					if (userInfo == null)
					{
						throw new BuzException("获取用户基本信息为空");
					}
					userInfo.appid = wxConfig.AppID;
					var settings = new JsonSerializerSettings()
					{
						NullValueHandling = NullValueHandling.Ignore
					};
					ViewBag.ExtInfo = JsonConvert.SerializeObject(new { page = page, state = state }, settings);
					ViewBag.UserInfo = JsonConvert.SerializeObject(userInfo, settings);
					return View();
				}
			}
			catch (BuzException ex)
			{
				return new JsonResultBase(false, ex.Message, (int)HttpStatusCode.InternalServerError);
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				return new JsonResultBase(false, "请求出错，" + ex.Message, (int)HttpStatusCode.InternalServerError);
			}
		}

		/// <summary>
		/// 发送模板消息
		/// </summary>
		/// <returns></returns>
		[HttpPost("sendtplmsg")]
		public IActionResult SendTplMsg([FromBody] WXTplMsgSendData vm)
		{
			Response.Headers.Add("Access-Control-Allow-Origin", "*");
			try
			{
				CheckParams();
				//var sessionCurrent = GetRawSessionFromRequest();
				var appConfig = wxAppConfigServ.LoadOrGet(vm.appid);
				tplMsgApi.Send(appConfig.AppID, appConfig.AppSecret, vm.touser, vm.tplid, vm.url, vm.topcolor, vm.xcxid, vm.xcxpage, vm.data);
				return new JsonResultBase(true);
			}
			catch (ArgumentException ex)
			{
				return new JsonResultBase(false, ex.Message, 400);
			}
			catch (BuzException ex)
			{
				return new JsonResultBase(false, ex.Message, 400);
			}
			catch (WXException ex)
			{
				return new JsonResultBase(false, ex.Message, 400);
			}
			catch (Exception ex)
			{
				logger.LogError(ex.InnerException ?? ex, ex.Message);
				return new JsonResultBase(false, ex.Message, 500);
			}
		}
		#region 辅助方法
		#endregion

		#region 具体事件处理
		/// <summary>
		/// 关注事件
		/// </summary>
		/// <param name="dicContent"></param>
		private void DoSubscribe(Dictionary<string, string> dicContent)
		{
			string openid = dicContent["FromUserName"];
			if (string.IsNullOrEmpty(openid))
			{
				return;
			}
			string eventKey = dicContent["EventKey"];
			string scene = string.Empty;
			if (!string.IsNullOrEmpty(eventKey) && eventKey.StartsWith("qrscene_"))
			{
				scene = eventKey.Substring(8);
			}
			if (!string.IsNullOrEmpty(scene))
			{
				if (logger.IsEnabled(LogLevel.Debug))
				{
					logger.LogDebug("新用户关注->场景值为：" + scene + "，openid：" + openid);
				}
			}
		}

		/// <summary>
		/// 扫码事件
		/// </summary>
		/// <param name="dicContent"></param>
		private void DoScan(Dictionary<string, string> dicContent)
		{

		}
		#endregion
	}
}